HELP = '''
功能：同步旧文件夹为新文件夹一模一样
运行方式：
python folder2folder.py 新文件夹 旧文件夹［参数］
-r 对调运行指令给定新旧文件夹顺序
--debug 只打印而不操作实际文件
--skip 跳过指定文件夹或文件类型， 如 --skip .svn,.zip
--nodelete 不要删除旧文件夹中的文件
--uselatest 如果旧文件夹的文件比较新，则用旧文件夹的文件替换old
'''
import os, sys, time, re
import shutil
from common import *
from hos import *
from colorama import Fore, init
init(autoreset=True)


class Folder:
    def __init__(self, path, skip_name=None):
        self.path = path 
        self.skip_name = skip_name
        if not self.skip_name:
            self.skip_name = []
        self.rpaths = self.get_rpaths()

    def get_rpaths(self):
        print(self.path)
        """
            返回Folder中所有文件相对Folder的路径
            self.skip_name: 跳过文件夹或某种类型的文件
        """
        ret = []
        ignore_list = []
        print_list = []
        for cur, dirs, files in os.walk(self.path):
            # 跳过隐藏文件夹
            if IsInHiddenFolder(cur):
                continue
            if '.hmignore' in files: # 20240805 新增，如果当前文件夹下有.hmignore文件，则忽略当前文件夹下所有文件
                # self.skip_name.append(cur) # 路径添加进去，因为反斜杠分隔符存在，到下面正则匹配会报错
                ignore_list.append(cur)
                
            # 跳过当前路径与self.skip_name一致的文件夹
            skip = False
            for s in self.skip_name+ignore_list:
                # 20240814 添加
                # 假设 s = /notebook/object_evidence 已经print跳过
                # 当 cur = /notebook/object_evidence/45001017 不要print跳过
                if OSis_match(cur, s):
                    is_print = True
                    for p in print_list:
                        if OSis_match(cur, p):
                            is_print = False
                            break
                    if is_print:
                        print(f"跳过文件夹{cur}")
                        print_list.append(cur)
                    skip = True
            if skip:
                continue

            for file in files:
                # 跳过隐藏文件和 指定类型的文件
                if not OSis_hidden(file) and \
                    not os.path.splitext(file)[1] in self.skip_name: # 跳过指定格式的文件
                    # 跳过符合正则表达式的文件
                    skip=False
                    for s in self.skip_name:
                        match = re.search(s, file)
                        if match and match.group()==file:
                            skip = True
                            break
                    if not skip:
                        rel_dir = cur.replace(self.path, "").strip(os.sep)
                        rpath = os.path.join(rel_dir, file)
                        ret.append(rpath)
                    # else:
                    #     print(f"跳过文件{file}")
        print(f"遍历文件夹{self.path}完成")
        return ret
        
    def fp(self, rpath):
        # 返回full path
        return OS.join(self.path, rpath)


def main(old_folder, new_folder, DEBUG=True):
    if OS.basename(old_folder) != OS.basename(new_folder):
        print("两个文件夹名字不一样...")
    skip_name = parse_argv("--skip")
    if skip_name:
        skip_name = skip_name.split(";")
    print("跳过", skip_name)
    old = Folder(old_folder, skip_name)
    new = Folder(new_folder, skip_name)

    old_rpaths = old.rpaths[:]
    for n in new.rpaths:
        newf = new.fp(n)
        oldf = old.fp(n)
        # new有old也有，如果new的修改时间比old新，则用new覆盖old
        if n in old.rpaths:
            old_rpaths.remove(n)
            new_modify = os.path.getmtime(newf)
            old_modify = os.path.getmtime(oldf)
            '''
                一般情况下，同是NTFS文件系统复制文件的话，复制的文件修改时间和原文件的修改时间是一样的，同是FAT32文件系统复制文件也一样。
                但如果把一个在NTFS文件系统上的文件复制到FAT32文件系统上时，文件修改时间会差1或者2秒，
                这是因为FAT32文件系统对文件的修改时间只用5位数记录秒数，因此FAT32文件系统上的文件修改时间只有偶数秒数
            '''
            if new_modify - old_modify > 3: # 新文件有改动
                if not DEBUG:
                    shutil.copy2(newf, oldf) # 新文件覆盖旧文件
                print(f"用new中的{n}覆盖old中的{n}\n")
            elif old_modify - new_modify > 3:
                if '--uselatest' in sys.argv:
                    shutil.copy2(oldf, newf) # 新文件覆盖旧文件
                    print(f"{Fore.YELLOW}用old中的{n}覆盖new中的{n}\n")
                else:
                    print(f"{Fore.YELLOW}请注意：old中的{n}比new中的新，请手动替换")  # 防止用户写反路径
        # new有old没有的，复制new到old
        else:
            print(f"复制new中的{n}到old中的{OSparent(oldf)}\n")
            if not DEBUG:
                if not OS.exists(OSparent(oldf)):
                    os.makedirs(OSparent(oldf), exist_ok=False) # 如果该文件夹里有文件会报错
                shutil.copy2(newf, oldf) 
    # old有new没有的，删除old
    for o in old_rpaths:
        if '--nodelete' not in sys.argv:
            print(f"删除old中的{o}\n")
            if not DEBUG:
                os.remove(old.fp(o))
                old_dir = os.path.dirname(old.fp(o))
                while OSis_empty(old_dir): # 删除空的文件夹
                    try:
                        print(f"删除old中的文件夹{old_dir}")
                        shutil.rmtree(old_dir)
                        old_dir = OSparent(old_dir)
                    except:
                        print(f"删除失败！")
                        break
    print("运行完成")
    

if __name__=="__main__":
    if len(sys.argv)<=1 or parse_argv("--help"):
        print(HELP)
    else:
        old_folder = sys.argv[2]
        new_folder = sys.argv[1]
        # 为了方便，不改运行指令，直接调换两个文件夹顺序
        if "-r" in sys.argv:
            sys.argv.remove("-r")
            old_folder = sys.argv[1]
            new_folder = sys.argv[2]
        # DEBUG = True, 只打印而不操作实际文件
        DEBUG = False
        if "--debug" in sys.argv:
            DEBUG = True
        main(old_folder, new_folder, DEBUG=DEBUG)